package org.iwidget.desktop.model;

import org.iwidget.desktop.core.*;
import org.iwidget.desktop.core.bsf.*;
import org.iwidget.desktop.core.javascript.IwidgetMethodsJS;
import org.iwidget.desktop.ui.WidgetFrame;
import org.iwidget.model.javascript.*;
import java.io.*;
import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.bsf.BSFEngine;
import org.apache.bsf.BSFManager;
import org.mozilla.javascript.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
/**
 *
 * @author Muhammad Hakim A
 */


public class WidgetElement
{
    class MyTimerTask extends TimerTask
    {

        public void run()
        {
            if(!inTimer && widgetLoaded && myFrame != null)
            {
                inTimer = true;
                triggerEvent("onTimer");
                inTimer = false;
            }
        }

        MyTimerTask()
        {
        }
    }


    // ctor
    public WidgetElement(Iwidget parent, String name)
    {
        inTimer = false;
        execCount = 0;
        widgetScript = "";
        isBSFLanguage = false;
        this.parent = parent;
        this.name = name;
        widgetLoaded = false;
        dontRememberWindowPosition = false;
        loadOnStartUp = false;
        iwidgetData = new IwidgetData();
        actions = new Hashtable();
        menuItems = new ArrayList();
        widgetClasses = new ArrayList();
        widgetInstances = new ArrayList();
        elementWindow = new ElementWindow(this);
        preferenceObjects = new ArrayList();
        preferenceHash = new Hashtable();
        uiObjects = new ArrayList();
        audioObjects = new ArrayList();
        subwidgetObjects = new ArrayList();
        widgetVersion = "1.0.0";
        iwidgetVersion = "1.0.0";
        debug = "off";
        portability = "all";
        setScriptLanguage(LANGUAGE_JAVASCRIPT);
    }

    public IwidgetData getIwidgetData()
    {
        return iwidgetData;
    }

    public Iwidget getParent()
    {
        return parent;
    }

    public WidgetFrame getUIComponent()
    {
        return myFrame;
    }

    public boolean isDontRememberWindowPosition()
    {
        return dontRememberWindowPosition;
    }

    public void setDontRememberWindowPosition(boolean b)
    {
        dontRememberWindowPosition = b;
    }

    public boolean isLoadOnStartUp()
    {
        return loadOnStartUp;
    }

    public void setLoadOnStartUp(boolean b)
    {
        loadOnStartUp = b;
    }

    public void setWindowJS(WindowElementJS windowJS)
    {
        this.windowJS = windowJS;
    }

    public String getName()
    {
        return name;
    }

    public ElementWindow getWindowJS()
    {
        return elementWindow;
    }

    public ArrayList getPreferenceObjects()
    {
        return preferenceObjects;
    }

    public Hashtable getPreferenceHash()
    {
        return preferenceHash;
    }

    public ArrayList getMenuElements()
    {
        return menuItems;
    }

    public Scriptable getScope()
    {
        return sharedScope;
    }

    public ArrayList getWidgetClasses()
    {
        return widgetClasses;
    }

    public void addWidgetClass(String s)
    {
        widgetClasses.add(s);
    }

    public ArrayList getWidgetInstances()
    {
        return widgetInstances;
    }

    public void addWidgetInstances(String s)
    {
        widgetInstances.add(s);
    }

    public void removeAllObjects()
    {
        while( subwidgetObjects.size() > 0 )
        {
            WidgetElement sub = (WidgetElement)subwidgetObjects.get( 0 );
            sub.close();
            subwidgetObjects.remove( 0 );
        }

        while( audioObjects.size() > 0 )
        {
            ElementSound oldC = (ElementSound)audioObjects.get( 0 );
            oldC.stop();
            audioObjects.remove( 0 );
        }

        while( preferenceObjects.size() > 0 )
        {
            preferenceHash.remove( preferenceObjects.get( 0 ) );
            preferenceObjects.remove( 0 );
        }
        preferenceHash = null;
        preferenceObjects = null;

        while( menuItems.size() > 0 )
                menuItems.remove( 0 );

        menuItems = null;

        while( widgetClasses.size() > 0 )
                widgetClasses.remove( 0 );

        widgetClasses = null;

        while( uiObjects.size() > 0 )
                uiObjects.remove( 0 );

        uiObjects = null;

        Enumeration e = actions.keys();
        while( e.hasMoreElements() )
                actions.remove( (String)e.nextElement() );

        actions = null;
    }

    public AboutElement getAboutElement()
    {
        return about;
    }

    public void setAboutElement(AboutElement about)
    {
        this.about = about;
    }

    public ElementIcon getIconElement(){
        return icon;
    }
    
    public void setIconElement(ElementIcon icon){
        this.icon = icon;
    }
    
    public void addMenu(WidgetMenuElement menuItem)
    {
        menuItems.add(menuItem);
    }

    public ActionElement getAction(String actionType)
    {
        try{
            return (ActionElement)actions.get(actionType);
        }catch(Exception e){
            System.out.println("action failure:" + actionType);
            e.printStackTrace();
            return null;
        }
    }

    public void addAction(String actionType, ActionElement action)
    {
        actions.put(actionType, action);
        if(actionType.equals("onTimer"))
        {
            int interval = action.getIntervalInMilliseconds();
            if(interval == 0)
                interval = 60000;
            MyTimerTask myTimerTask = new MyTimerTask();
            parent.getTimer().schedule(myTimerTask, interval, interval);
        }
    }

    public void triggerEvent(String actionType)
    {
        if(actionType.equals("onLoad"))
        {
            loadPreferences();
            widgetLoaded = true;
        } else
        if(actionType.equals("onUnload"))
        {
            savePreferences();
            widgetLoaded = false;
        } else
        if(actionType.equals("onPreferencesChanged"))
            savePreferences();
        if(actions != null)
        {
            ActionElement action = (ActionElement)actions.get(actionType);
            if(action != null)
                try
                {
                    String script = action.getScript();
                    if(script != null)
                        executeScript(this, action.getScript(), action.getType());
                    else
                    if(action.getFile() != null)
                        executeScriptFile(this, action.getFile());
                    script = null;
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
        }
    }

    public void loadPreferences()
    {
        try
        {
            Properties props = new Properties();
            FileInputStream is = new FileInputStream("./prefs/" + getName() + ".pref");
            props.load(is);
            is.close();
            if(!isDontRememberWindowPosition())
            {
                elementWindow.setHeight(Integer.parseInt(props.getProperty("window.height")));
                elementWindow.setWidth(Integer.parseInt(props.getProperty("window.width")));
                elementWindow.setX(Integer.parseInt(props.getProperty("window.x")));
                elementWindow.setY(Integer.parseInt(props.getProperty("window.y")));
            }
            for(int iCtr = 0; iCtr < preferenceObjects.size(); iCtr++)
            {
                ElementPreferences pref = (ElementPreferences)preferenceObjects.get(iCtr);
                try
                {
                    pref.setValue(props.getProperty(pref.getName(), ""));
                }
                catch(Exception e)
                {
                    String defaultValue = pref.getDefaultValue();
                    pref.setValue(defaultValue);
                }
                if(pref.getType().equals("password"))
                {
                    String value = pref.getValue();
                    if(value == null)
                        value = "";
                    value = Iwidget.decrypt(value);
                    pref.setValue(value);
                }
            }

        }
        catch(Exception ex)
        {
            loadOldPreferences();
        }
    }

    private void loadOldPreferences()
    {
        try
        {
            FileReader fr = null;
            try
            {
                fr = new FileReader("./prefs/" + getName() + ".pref");
            }
            catch(Exception ex)
            {
                fr = new FileReader("./library/" + getName() + "/widget.pref");
            }
            BufferedReader stream = new BufferedReader(fr);
            if(!isDontRememberWindowPosition())
                try
                {
                    elementWindow.setHeight(Integer.parseInt(stream.readLine()));
                    elementWindow.setWidth(Integer.parseInt(stream.readLine()));
                    elementWindow.setX(Integer.parseInt(stream.readLine()));
                    elementWindow.setY(Integer.parseInt(stream.readLine()));
                    getUIComponent().setSize(elementWindow.getWidth(), elementWindow.getHeight());
                    getUIComponent().setLocation(elementWindow.getX(), elementWindow.getY());
                }
                catch(Exception e) { }
            for(int iCtr = 0; iCtr < preferenceObjects.size();)
            {
                ElementPreferences pref = (ElementPreferences)preferenceObjects.get(iCtr);
                try
                {
                    pref.setValue(stream.readLine());
                    continue;
                }
                catch(Exception e)
                {
                    String defaultValue = pref.getDefaultValue();
                    pref.setValue(defaultValue);
                    iCtr++;
                }
            }

            stream.close();
        }
        catch(Exception e) { }
    }

    public void savePreferences()
    {
        Properties props = new Properties();
        if(!isDontRememberWindowPosition())
        {
            props.put("window.height", "" + elementWindow.getHeight());
            props.put("window.width", "" + elementWindow.getWidth());
            props.put("window.x", "" + elementWindow.getX());
            props.put("window.y", "" + elementWindow.getY());
        }
        for(int iCtr = 0; iCtr < preferenceObjects.size(); iCtr++)
        {
            ElementPreferences pref = (ElementPreferences)preferenceObjects.get(iCtr);
            if(pref.getNotSaved())
                continue;
            String value = pref.getValue();
            if(value == null || value.length() == 0)
                value = pref.getDefaultValue();
            if(pref.getType().equals("password"))
                value = Iwidget.encrypt(value);
            props.put(pref.getName(), value);
        }

        try
        {
            FileOutputStream os = new FileOutputStream("./prefs/" + getName() + ".pref");
            props.store(os, "");
            os.close();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public void executeScriptFile(WidgetElement widget, String scriptFile)
        throws Exception
    {
        StringBuffer sb = IwidgetRepository.getInstance().getPage(widget.getName(), scriptFile);
        executeScript(widget, sb.toString(), scriptFile);
        sb = null;
    }

    public void executeScript(WidgetElement widget, String script, String tagName)
        throws Exception
    {
        if(getScriptLanguage().equals("javascript"))
            executeJavaScript(widget, script, tagName);
        else
        if(isBSFLanguage)
            executeBSF(widget, script, tagName);
        else
            getParent().getDebugFrame().addText("ERROR:Scripting language unsupported:" + widget.getName() + ":" + getScriptLanguage());
    }

    /*public void executeJudoScript(WidgetElement widget, String script, String tagName)
        throws Exception
    {
        try
        {
            handlePostExecChanges();
        }
        catch(Exception e)
        {
            getParent().getDebugFrame().addText("SCRIPT ERROR:" + elementWindow.getTitle());
            getParent().getDebugFrame().addText("             " + e.getMessage());
            System.out.println("Exception caught in:" + elementWindow.getTitle());
            e.printStackTrace();
        }
    }*/

    public void executeBSF(WidgetElement widget, String script, String tagName)
        throws Exception
    {
        try
        {
            String execScript = script;
            if(widgetScript.length() == 0)
                widgetScript = script;
            engine.exec(tagName, 0, 0, execScript);
            handlePostExecChanges();
        }
        catch(Exception e)
        {
            getParent().getDebugFrame().addText("SCRIPT ERROR:" + elementWindow.getTitle());
            getParent().getDebugFrame().addText("             " + e.getMessage());
            System.out.println("Exception caught in:" + elementWindow.getTitle());
            e.printStackTrace();
        }
    }

    public void executeJavaScript(WidgetElement widget, String script, String tagName)
        throws Exception
    {
        Context cx = Context.enter();
        try
        {
            cx.evaluateString(sharedScope, script, tagName, 1, null);
            execCount++;
            if(execCount > 100)
            {
                System.gc();
                execCount = 0;
            }
            handlePostExecChanges();
            Context.exit();
        }
        catch(JavaScriptException e)
        {
            getParent().getDebugFrame().addText("SCRIPT ERROR:" + elementWindow.getTitle());
            getParent().getDebugFrame().addText("             " + e.getMessage());
            System.out.println("Exception caught in:" + elementWindow.getTitle());
            e.printStackTrace();
        }
        catch(Exception e)
        {
            getParent().getDebugFrame().addText("\n***SCRIPT ERROR:" + elementWindow.getTitle());
            getParent().getDebugFrame().addText("***************:" + Iwidget.replace(e.toString(), "<cmd;> ", "", 0) + "\n");
            System.out.println("Exception caught in:" + elementWindow.getTitle());
            e.printStackTrace();
        }
        cx = null;
    }

    private void handlePostExecChanges()
    {
        boolean propertyChanged = false;
        if(getUIComponent() != null && elementWindow.hasChanged())
        {
            getUIComponent().setSize(elementWindow.getWidth(), elementWindow.getHeight());
            getUIComponent().setLocation(elementWindow.getX(), elementWindow.getY());
            elementWindow.clearChange();
            getUIComponent().repaint();
        }
        if(uiObjects != null)
        {
            for(int iCtr = 0; iCtr < uiObjects.size(); iCtr++)
            {
                Object obj2 = uiObjects.get(iCtr);
                if(obj2 instanceof ElementImage)
                {
                    ElementImage objectJS = (ElementImage)obj2;
                    if(objectJS.hasChanged() && objectJS.getUIComponent() != null)
                    {
                        propertyChanged = true;
                        objectJS.clearChange();
                    }
                } else
                if(obj2 instanceof ElementTextField)
                {
                    ElementTextField objectJS = (ElementTextField)obj2;
                    if(objectJS.hasChanged() && objectJS.getUIComponent() != null)
                    {
                        propertyChanged = true;
                        objectJS.clearChange();
                    }
                } else
                if(obj2 instanceof ElementTextArea)
                {
                    ElementTextArea objectJS = (ElementTextArea)obj2;
                    if(objectJS.hasChanged() && objectJS.getUIComponent() != null)
                    {
                        propertyChanged = true;
                        objectJS.clearChange();
                    }
                } else
                if(obj2 instanceof ElementScroller)
                {
                    ElementScroller objectJS = (ElementScroller)obj2;
                    if(objectJS.hasChanged() && objectJS.getUIComponent() != null)
                    {
                        propertyChanged = true;
                        objectJS.clearChange();
                    }
                }
                if(getUIComponent() != null && propertyChanged)
                    getUIComponent().repaint();
            }

        }
    }

    public synchronized Object executeScriptFunction(String function, String args[])
        throws Exception
    {
        if(getScriptLanguage().equals("javascript"))
            return executeJavaScriptFunction(function, args);
        if(isBSFLanguage)
        {
            return executeBSFFunction(function, args);
        } else
        {
            getParent().getDebugFrame().addText("ERROR:Scripting language unsupported:" + getName() + ":" + getScriptLanguage());
            return null;
        }
    }

    public synchronized Object executeBSFFunction(String function, String args[])
        throws Exception
    {
        try{
            return engine.call(null, function, args);
        }catch(Exception e){
            parent.getDebugFrame().addText("SYSTEM:Error:Call to function " + function + "() failed");
            e.printStackTrace();
            return null;
        }
    }

    public synchronized Object executeJavaScriptFunction(String function, String args[])
        throws Exception
    {
        Scriptable scope;
        Function f;
        Context cx = Context.enter();
        scope = cx.newObject(sharedScope);
        scope.setPrototype(sharedScope);
        scope.setParentScope(null);
        Object obj = scope.get(function, scope);
        if(!(obj instanceof Function))
        {
            parent.getDebugFrame().addText("SYSTEM:Error:Attempt to call non-function:" + function);
            
        }
        f = (Function)obj;
        try{
            Object result;
            result = f.call(Context.getCurrentContext(), scope, scope, args);
            Context.exit();
            cx = null;
            return result;
        }catch(Exception ex){
            parent.getDebugFrame().addText("SYSTEM:Error:Call to function " + function + "() failed");
            return null;
        }
    }

    public void widgetLoaded()
    {
        if(!isBSFLanguage)
            if(getScriptLanguage().equals("javascript"))
            {
                createContext();
            } else
            {
                getParent().getDebugFrame().addText("ERROR:Scripting language unsupported:" + getName() + ":" + getScriptLanguage());
                return;
            }
        triggerEvent("onLoad");
        myFrame = new WidgetFrame(this);
        for(int iCtr = 0; iCtr < subwidgetObjects.size(); iCtr++)
        {
            WidgetElement object = (WidgetElement)subwidgetObjects.get(iCtr);
            object.widgetLoaded();
        }

    }

    public Context createContext()
    {
        Context cx = Context.enter(Context.getCurrentContext());
        try
        {
            ScriptableObject.defineClass(sharedScope, org.iwidget.desktop.core.javascript.IwidgetURL.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.desktop.core.javascript.IwidgetSystem.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.desktop.core.javascript.IwidgetScreen.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.desktop.core.javascript.IwidgetClipboard.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.desktop.core.javascript.IwidgetMouse.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.model.javascript.ImgElementJS.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.model.javascript.TextFieldElementJS.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.model.javascript.FormElementJS.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.model.javascript.TextAreaElementJS.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.model.javascript.ScrollElementJS.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.model.javascript.SoundElementJS.class);
            ScriptableObject.defineClass(sharedScope, org.iwidget.model.javascript.PreferencesJS.class);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        try
        {
            Scriptable widgetOut = Context.toObject(this, sharedScope);
            sharedScope.put("widget", sharedScope, widgetOut);
            Scriptable out = cx.newObject(sharedScope, "screen", null);
            sharedScope.put("screen", sharedScope, out);
            out = cx.newObject(sharedScope, "clipboard", null);
            sharedScope.put("clipboard", sharedScope, out);
            out = cx.newObject(sharedScope, "system", null);
            sharedScope.put("system", sharedScope, out);
            out = cx.newObject(sharedScope, "mouse", null);
            sharedScope.put("mouse", sharedScope, out);
            if(windowJS != null)
                sharedScope.put(elementWindow.getName(), sharedScope, windowJS);
            if(prefsJS != null)
                sharedScope.put("preferences", sharedScope, prefsJS);
            for(int iCtr = 0; iCtr < getWidgetClasses().size();)
            {
                String className = (String)getWidgetClasses().get(iCtr);
                try
                {
                    Class s = IwidgetRepository.getInstance().getClass(className);
                    ScriptableObject.defineClass(sharedScope, s);
                    continue;
                }
                catch(Exception e)
                {
                    parent.getDebugFrame().addText("SYSTEM:Error:Unable to load class: " + className);
                    e.printStackTrace();
                    iCtr++;
                }
            }

            for(int iCtr = 0; iCtr < getWidgetInstances().size(); iCtr++)
            {
                String className = (String)getWidgetInstances().get(iCtr);
                try
                {
                    Class s = IwidgetRepository.getInstance().getClass(className);
                    ScriptableObject.defineClass(sharedScope, s);
                    ScriptableObject instance = (ScriptableObject)s.newInstance();
                    out = cx.newObject(sharedScope, instance.getClassName(), null);
                    sharedScope.put(instance.getClassName(), sharedScope, out);
                }
                catch(Exception e)
                {
                    parent.getDebugFrame().addText("SYSTEM:Error:Unable to load class instance: " + className);
                    e.printStackTrace();
                }
            }

        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        Context.exit();
        return cx;
    }

    public String getWidgetVersion()
    {
        return widgetVersion;
    }

    public void setWidgetVersion(String string)
    {
        widgetVersion = string;
    }

    public String getIwidgetVersion()
    {
        return iwidgetVersion;
    }

    public void setIwidgetVersion(String string)
    {
        iwidgetVersion = string;
    }

    public String getPortability()
    {
        return portability;
    }

    public void setPortability(String string)
    {
        portability = string;
    }

    public String getDebug()
    {
        return debug;
    }

    public void setDebug(String string)
    {
        debug = string;
    }

    public String getScriptLanguage()
    {
        return scriptLanguage;
    }

    public void setScriptLanguage(String string)
    {
        scriptLanguage = string;
        if(scriptLanguage.equals("javascript"))
        {
            Context cx = Context.enter(Context.getCurrentContext());
            if(sharedScope == null)
                sharedScope = new IwidgetMethodsJS(parent, cx);
            Context.exit();
            prefsJS = new PreferencesJS();
        } else
        if(scriptLanguage.equals("python"))
        {
            manager = new BSFManager();
            try
            {
                engine = manager.loadScriptingEngine("jython");
                isBSFLanguage = true;
            }
            catch(Exception e)
            {
                parent.getDebugFrame().addText("SYSTEM:Error:Python parser not found");
                e.printStackTrace();
            }
        }
        if(isBSFLanguage)
            try
            {
                manager.declareBean("screen", new IwidgetScreenBSF(), org.iwidget.desktop.core.bsf.IwidgetScreenBSF.class);
                manager.declareBean("clipboard", new IwidgetClipboardBSF(), org.iwidget.desktop.core.bsf.IwidgetClipboardBSF.class);
                manager.declareBean("mouse", new IwidgetMouseBSF(this), org.iwidget.desktop.core.bsf.IwidgetMouseBSF.class);
                manager.declareBean("system", new IwidgetSystemBSF(this), org.iwidget.desktop.core.bsf.IwidgetSystemBSF.class);
                manager.declareBean("widget", this, org.iwidget.desktop.model.WidgetElement.class);
                manager.declareBean("preferences", preferenceHash, java.util.Hashtable.class);
                String script = getInitScript(scriptLanguage);
                if(script.length() > 0)
                    engine.exec("init", 0, 0, script);
            }
            catch(Exception e)
            {
                parent.getDebugFrame().addText("SYSTEM:Error:Problem initializing parser");
                e.printStackTrace();
            }
    }

    private String getInitScript(String language)
    {
        StringBuffer sb = new StringBuffer();
        try
        {
            BufferedReader fr = new BufferedReader(new FileReader("init/init." + language));
            for(String s = fr.readLine(); s != null; s = fr.readLine())
                sb.append(s).append("\n");

            fr.close();
        }
        catch(Exception e)
        {
            System.out.println("SYSTEM:Warning:No initialization script found for language:" + language);
            parent.getDebugFrame().addText("SYSTEM:Warning:No initialization script found for language:" + language);
        }
        return sb.toString();
    }

    public boolean constructWidget(String widgetName, String fileName)
    {
        try{
            StringBuffer sb = IwidgetRepository.getInstance().getPage(widgetName, fileName);
            if(sb == null)
                return false; //gagal , widget.xml tak terbaca
            
            String xmlData = sb.toString();
            xmlData = Iwidget.replace(xmlData, "<script>", "<script><![CDATA[", 0);
            xmlData = Iwidget.replace(xmlData, "</script>", "]]></script>", 0);
            xmlData = Iwidget.replace(xmlData, "<string>", "<string><![CDATA[", 0);
            xmlData = Iwidget.replace(xmlData, "</string>", "]]></string>", 0);
            xmlData = Iwidget.replace(xmlData, "<defaultValue>", "<defaultValue><![CDATA[", 0);
            xmlData = Iwidget.replace(xmlData, "</defaultValue>", "]]></defaultValue>", 0);
            xmlData = Iwidget.replace(xmlData, "<data>", "<data><![CDATA[", 0);
            xmlData = Iwidget.replace(xmlData, "</data>", "]]></data>", 0);
            
            InputSource inSource = new InputSource(new StringReader(xmlData));
            DocumentBuilderFactory docBuilder = DocumentBuilderFactory.newInstance();
            DocumentBuilder parser = docBuilder.newDocumentBuilder();
            Document doc = parser.parse(inSource);
            org.w3c.dom.Element element = doc.getDocumentElement();
            NodeList nodes = element.getChildNodes();
            
            for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
            {
                org.w3c.dom.Node childNode = nodes.item(iCtr);
                String nodeName = childNode.getNodeName();
                if(nodeName.equals("about"))
                {
                    parseAbout(childNode);
                    continue;
                }
                if (nodeName.equals("icon")){
                    parseIcon(childNode);
                    continue;
                }
                if(nodeName.equals("action"))
                {
                    parseActions(childNode);
                    continue;
                }
                if(nodeName.equals("code"))
                {
                    parseCode(childNode);
                    continue;
                }
                if(nodeName.equals("debug"))
                {
                    parseDebug(childNode);
                    continue;
                }
                if(nodeName.equals("iwidgetVersion"))
                {
                    parseIwidgetVersion(childNode);
                    continue;
                }
                if(nodeName.equals("image"))
                {
                    parseImages(childNode);
                    continue;
                }
                if(nodeName.equals("menu"))
                {
                    parseMenu(childNode);
                    continue;
                }
                if(nodeName.equals("option"))
                {
                    parseOption(childNode);
                    continue;
                }
                if(nodeName.equals("portability"))
                {
                    parsePortability(childNode);
                    continue;
                }
                if(nodeName.equals("preference"))
                {
                    parsePreference(childNode);
                    continue;
                }
                if(nodeName.equals("language"))
                {
                    parseScriptLanguage(childNode);
                    continue;
                }
                if(nodeName.equals("scroller"))
                {
                    parseScroller(childNode);
                    continue;
                }
                if(nodeName.equals("sound"))
                {
                    parseSound(childNode);
                    continue;
                }
                if(nodeName.equals("subwidget"))
                {
                    parseSubwidget(childNode);
                    continue;
                }
                if(nodeName.equals("text"))
                {
                    parseText(childNode);
                    continue;
                }
                if(nodeName.equals("textarea"))
                {
                    parseTextArea(childNode);
                    continue;
                }
                if(nodeName.equals("widgetVersion"))
                {
                    parseWidgetVersion(childNode);
                    continue;
                }
                if(nodeName.equals("window"))
                    parseWindow(childNode);
            }

            getWindowJS().setTitle(widgetName);
            return true;
        }catch(Exception e){
            e.printStackTrace();
            getParent().getDebugFrame().addText("SYSTEM:Error:Unable to load widget properites for: " + widgetName);
            return false;
        }
    }

    private void parseAbout(org.w3c.dom.Node node)
        throws Exception
    {
        AboutElement abt = new AboutElement(this);
        abt.parse(node);
        setAboutElement(abt);
    }

    private void parseIcon(org.w3c.dom.Node node)
        throws Exception
    {
        ElementIcon icn = new ElementIcon(this);
        icn.parse(node);
        setIconElement(icn);
    }
            
    private void parseActions(org.w3c.dom.Node node)
        throws Exception
    {
        ActionElement action = new ActionElement();
        action.parse(node);
        addAction(action.getType(), action);
    }

    private void parseCode(org.w3c.dom.Node node)
        throws Exception
    {
        NamedNodeMap map = node.getAttributes();
        for(int iCtr = 0; iCtr < map.getLength(); iCtr++)
        {
            org.w3c.dom.Node attr = map.item(iCtr);
            if(attr.getNodeName().equals("class"))
                addWidgetClass(attr.getNodeValue());
        }

        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            String nodeName = childNode.getNodeName();
            String nodeValue = childNode.getNodeValue();
            if(childNode.getFirstChild() != null && nodeName.equals("class"))
                addWidgetClass(childNode.getFirstChild().getNodeValue());
        }

    }

    private void parseDebug(org.w3c.dom.Node node)
        throws Exception
    {
        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            setDebug(childNode.getNodeValue());
        }

    }

    private void parseIwidgetVersion(org.w3c.dom.Node node)
        throws Exception
    {
        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            setIwidgetVersion(childNode.getNodeValue());
        }

    }

    private void parseImages(org.w3c.dom.Node node)
        throws Exception
    {
        ElementImage object = new ElementImage(this);
        object.parse(node);
        if(getScriptLanguage().equals("javascript"))
        {
            ImgElementJS imgElement = new ImgElementJS(this, object.getName());
            imgElement.setElementData(object);
            getScope().put(object.getName(), getScope(), imgElement);
        } else
        if(isBSFLanguage)
            manager.declareBean(object.getName(), object, org.iwidget.desktop.model.ElementImage.class);
        uiObjects.add(object);
    }

    private void parseMenu(org.w3c.dom.Node node)
        throws Exception
    {
        WidgetMenuElement menuItem = new WidgetMenuElement(this);
        menuItem.parse(node);
        addMenu(menuItem);
    }

    private void parseOption(org.w3c.dom.Node node)
        throws Exception
    {
        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            if(childNode.getNodeValue().equals("dontRememberWindowPosition"))
            {
                setDontRememberWindowPosition(true);
                continue;
            }
            if(childNode.getNodeValue().equals("loadOnStartUp"))
                setLoadOnStartUp(true);
        }

    }

    private void parsePortability(org.w3c.dom.Node node)
        throws Exception
    {
        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            setPortability(childNode.getNodeValue());
        }

    }

    private void parsePreference(org.w3c.dom.Node node)
        throws Exception
    {
        ElementPreferences object = new ElementPreferences(this);
        object.parse(node);
        if(getScriptLanguage().equals("javascript"))
        {
            PreferencesJS element = new PreferencesJS(this, object.getName());
            element.setElementData(object);
            getScope().put(object.getName(), prefsJS, element);
        }
        getPreferenceObjects().add(object);
        getPreferenceHash().put(object.getName(), object);
    }

    private void parseScriptLanguage(org.w3c.dom.Node node)
        throws Exception
    {
        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            scriptLanguage = childNode.getNodeValue();
            if(!scriptLanguage.equals("javascript") && !scriptLanguage.equals("python"))
                getParent().getDebugFrame().addText("SYSTEM:Error:Language invalid:" + getScriptLanguage());
        }

    }

    private void parseScroller(org.w3c.dom.Node node)
        throws Exception
    {
        ElementScroller object = new ElementScroller(this);
        object.parse(node);
        if(getScriptLanguage().equals("javascript"))
        {
            ScrollElementJS imgElement = new ScrollElementJS(this, object.getName());
            imgElement.setElementData(object);
            getScope().put(object.getName(), getScope(), imgElement);
        } else
        if(isBSFLanguage)
            manager.declareBean(object.getName(), object, org.iwidget.desktop.model.ElementScroller.class);
        uiObjects.add(object);
    }

    private void parseSound(org.w3c.dom.Node node)
        throws Exception
    {
        ElementSound object = new ElementSound(this);
        object.parse(node);
        if(getScriptLanguage().equals("javascript"))
        {
            SoundElementJS element = new SoundElementJS(this, object.getName());
            element.setElementData(object);
            getScope().put(object.getName(), getScope(), element);
        } else
        if(isBSFLanguage)
            manager.declareBean(object.getName(), object, org.iwidget.desktop.model.ElementSound.class);
        audioObjects.add(object);
    }

    private void parseSubwidget(org.w3c.dom.Node node)
    {
        String subwidgetName = null;
        String subwidgetFileName = null;
        NamedNodeMap map = node.getAttributes();
        for(int iCtr = 0; iCtr < map.getLength(); iCtr++)
        {
            org.w3c.dom.Node attr = map.item(iCtr);
            if(attr.getNodeName().equals("name"))
            {
                subwidgetName = attr.getNodeValue();
                continue;
            }
            if(attr.getNodeName().equals("file"))
                subwidgetFileName = attr.getNodeValue();
        }

        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            String nodeName = childNode.getNodeName();
            String nodeValue = childNode.getNodeValue();
            if(childNode.getFirstChild() == null)
                continue;
            if(nodeName.equals("name"))
            {
                subwidgetName = childNode.getFirstChild().getNodeValue();
                continue;
            }
            if(nodeName.equals("file"))
                subwidgetFileName = childNode.getFirstChild().getNodeValue();
        }

        if(subwidgetName != null && subwidgetFileName != null)
        {
            WidgetElement object = new WidgetElement(getParent(), getName());
            object.constructWidget(getName(), subwidgetFileName);
            object.parentWidget = this;
            subwidgetObjects.add(object);
            Context cx = Context.enter(Context.getCurrentContext());
            Scriptable widgetOut = Context.toObject(object, sharedScope);
            sharedScope.put(object.getName(), sharedScope, widgetOut);
            Context.exit();
        } else
        {
            getParent().getDebugFrame().addText("SYSTEM:Error:Cannot load sub-widget:" + subwidgetName);
        }
    }

    private void parseText(org.w3c.dom.Node node)
        throws Exception
    {
        ElementTextField object = new ElementTextField(this);
        object.parse(node);
        if(getScriptLanguage().equals("javascript"))
        {
            TextFieldElementJS txtElement = new TextFieldElementJS(this, object.getName());
            txtElement.setElementData(object);
            getScope().put(object.getName(), getScope(), txtElement);
        } else
        if(isBSFLanguage)
            manager.declareBean(object.getName(), object, org.iwidget.desktop.model.ElementTextField.class);
        uiObjects.add(object);
    }

    private void parseTextArea(org.w3c.dom.Node node)
        throws Exception
    {
        ElementTextArea object = new ElementTextArea(this);
        object.parse(node);
        if(getScriptLanguage().equals("javascript"))
        {
            TextAreaElementJS txtElement = new TextAreaElementJS(this, object.getName());
            txtElement.setElementData(object);
            getScope().put(object.getName(), getScope(), txtElement);
        } else
        if(isBSFLanguage)
            manager.declareBean(object.getName(), object, org.iwidget.desktop.model.ElementTextArea.class);
        uiObjects.add(object);
    }

    private void parseWidgetVersion(org.w3c.dom.Node node)
        throws Exception
    {
        NodeList nodes = node.getChildNodes();
        for(int iCtr = 0; iCtr < nodes.getLength(); iCtr++)
        {
            org.w3c.dom.Node childNode = nodes.item(iCtr);
            setWidgetVersion(childNode.getNodeValue());
        }

    }

    private void parseWindow(org.w3c.dom.Node node)
        throws Exception
    {
        ElementWindow object = new ElementWindow(this);
        object.parse(node);
        if(getScriptLanguage().equals("javascript"))
        {
            WindowElementJS window = new WindowElementJS(this, object.getName());
            window.setElementData(object);
            setWindowJS(window);
        } else
        if(isBSFLanguage)
            manager.declareBean(object.getName(), object, org.iwidget.desktop.model.ElementWindow.class);
        elementWindow = object;
    }

    public void close()
    {
        triggerEvent("onUnload");
        if(getUIComponent() != null)
            getUIComponent().dispose();
        removeAllObjects();
    }

    public static final String LANGUAGE_JAVASCRIPT = "javascript";
    public static final String LANGUAGE_PYTHON = "python";
    private Iwidget parent;
    private WidgetElement parentWidget;
    private String debug;
    private String widgetVersion;
    private String iwidgetVersion;
    private String name;
    private String portability;
    private String scriptLanguage;
    private AboutElement about;
    private ElementIcon icon;
    private Hashtable actions;
    private ArrayList menuItems;
    public ArrayList uiObjects;
    public ArrayList audioObjects;
    public ArrayList subwidgetObjects;
    private Hashtable preferenceHash;
    private ArrayList preferenceObjects;
    private ArrayList widgetClasses;
    private ArrayList widgetInstances;
    private boolean dontRememberWindowPosition;
    private boolean loadOnStartUp;
    private boolean widgetLoaded;
    private Scriptable sharedScope;
    public ElementWindow elementWindow;
    public PreferencesJS prefsJS;
    public WindowElementJS windowJS;
    public BSFManager manager;
    public BSFEngine engine;
    private WidgetFrame myFrame;
    private IwidgetData iwidgetData;
    boolean inTimer;
    int execCount;
    private String widgetScript;
    public boolean isBSFLanguage;


}